from Data_Type import *
from MEMORY import *
from Register_File import *

I_opcodes = (0b0010011, 0b0000011, 0b1100111, 0b1110011, 0b0000111, 0b0011011)


class micro_option:
    def __init__(self):
        self.name = ""
        self.type = ''
        self.size = 0  # 2 -> 32位字    1 -> 16位半字   0 -> 8位字节
        self.read_mem = False
        self.write_mem = False
        self.write_ex2reg = False
        self.write_mem2reg = False
        self.jump = False
        self.unsigned = False
        self.stack = False






def ID(Instr):
    opcode = data_slice(Instr, 6, 0)
    rs1 = 0
    rs2 = 0
    rd = 0
    imm = 0
    micro_opt = micro_option()
    No_Such_Instr = False                  
    if opcode == 0b0110011:         ################### R type
        micro_opt.type = "R"
        micro_opt.write_ex2reg = True
        funct7 = data_slice(Instr, 31, 25)
        funct3 = data_slice(Instr, 14, 12)
        rs2 = data_slice(Instr, 24, 20)
        rs1 = data_slice(Instr, 19, 15)
        rd = data_slice(Instr, 11, 7)
        if funct3 == 0b000:
            if funct7 == 0b0000000:             # add
                micro_opt.name = "add"                      
            elif funct7 == 0b0100000:           # sub
                micro_opt.name = "sub"                    
            elif funct7 == 0b0000001:           # mul
                micro_opt.name = "mul"
            else:
                No_Such_Instr = True                    
        elif funct3 == 0b001:
            if funct7 == 0b0000000:             # sll
                micro_opt.name = "sll"
        elif funct3 == 0b010:
            if funct7 == 0b0000000:             # slt
                micro_opt.name = "slt"
        elif funct3 == 0b011:
            pass
        elif funct3 == 0b100:
            if funct7 == 0b0000000:             # xor
                micro_opt.name = "xor"
            if funct7 == 0b0000001:             # div
                micro_opt.name = "div"
        elif funct3 == 0b101:
            pass
        elif funct3 == 0b110:
            if funct7 == 0b0000000:             # or
                micro_opt.name = "or"
            if funct7 == 0b0000001:             # rem
                micro_opt.name = "rem"
        elif funct3 == 0b111:
            pass
        else:
            No_Such_Instr = True  
    
    elif opcode in I_opcodes:         ################### I type
        imm_u = data_slice(Instr, 31, 20)
        imm = sign_expend(imm_u,12)          # 符号拓展12位
        rs1 = data_slice(Instr, 19, 15)     # 基地址寄存器
        funct3 = data_slice(Instr, 14, 12)
        rd = data_slice(Instr, 11, 7)
        funct6 = data_slice(Instr, 31, 26)
        shamt = data_slice(Instr, 25, 20)
        if opcode == 0b0000011:
            if funct3 == 0b000:
                micro_opt.name = "lb"
                micro_opt.size = 0
                micro_opt.write_mem2reg = True
                micro_opt.read_mem = True
                if rs1 == 2:
                    micro_opt.stack = True
            elif funct3 == 0b001:
                micro_opt.name = "lh"
                micro_opt.write_mem2reg = True
                micro_opt.read_mem = True
                micro_opt.size = 1
                if rs1 == 2:
                    micro_opt.stack = True
            elif funct3 == 0b010:
                micro_opt.name = "lw"
                micro_opt.write_mem2reg = True
                micro_opt.read_mem = True
                micro_opt.size = 2
                if rs1 == 2:
                    micro_opt.stack = True
            elif funct3 == 0b100:
                micro_opt.name = "lbu"
                micro_opt.write_mem2reg = True
                micro_opt.read_mem = True
                micro_opt.size = 0
                micro_opt.unsigned = True
                if rs1 == 2:
                    micro_opt.stack = True
            elif funct3 == 0b101:
                micro_opt.name = "lhu"
                micro_opt.write_mem2reg = True
                micro_opt.read_mem = True
                micro_opt.size = 1
                micro_opt.unsigned = True
                if rs1 == 2:
                    micro_opt.stack = True
            elif funct3 == 0b110:
                micro_opt.name = "lwu"
                micro_opt.write_mem2reg = True
                micro_opt.read_mem = True
                micro_opt.size = 2
                micro_opt.unsigned = True
                if rs1 == 2:
                    micro_opt.stack = True
            else:
                No_Such_Instr = True

        elif opcode == 0b0010011:
            micro_opt.write_ex2reg = True
            if funct3 == 0b000:
                micro_opt.name = "addi"  # addi
            elif funct3 == 0b010:
                micro_opt.name = "slti"  # slti
            elif funct3 == 0b011:
                micro_opt.name = "sltiu"  # sltiu
                micro_opt.unsigned = True
                imm = imm_pre
            elif funct3 == 0b100:
                micro_opt.name = "xori"  # xori
            elif funct3 == 0b110:
                micro_opt.name = "ori"  # ori
            elif funct3 == 0b111:
                micro_opt.name = "andi"  # andi
            elif funct3 == 0b001:  # slli
                micro_opt.name = "slli"
            else:
                No_Such_Instr = True

        
        elif opcode == 0b1100111:
            micro_opt.name = "jalr"
            micro_opt.jump = True
            micro_opt.write_ex2reg = True
        elif opcode == 0b1110011:
            micro_opt.name = "ecall"
        else:
            No_Such_Instr = True

    elif opcode == 0b1101111:  # J-type
        micro_opt.name = "jal"
        micro_opt.jump = True
        micro_opt.write_ex2reg = True
        idx_3112 = data_slice(Instr, 31, 12)
        imm_pre = (data_slice(idx_3112, 19, 19) << 20) | (data_slice(idx_3112, 7, 0) << 12) | (
                    data_slice(idx_3112, 8, 8) << 11) | (data_slice(idx_3112, 18, 9) << 1)
        imm = sign_expend(imm_pre, 21)
        rd = data_slice(Instr, 11, 7)
    
    elif opcode == 0b0110111:  # U-type
        micro_opt.name = "lui"
        micro_opt.write_ex2reg = True
        rd = data_slice(Instr, 11, 7)
        imm = data_slice(Instr, 31, 12) << 12
    elif opcode == 0b0010111:
        micro_opt.name = "auipc"
        micro_opt.write_ex2reg = True
        rd = data_slice(Instr, 11, 7)
        imm = data_slice(Instr, 31, 12) << 12
    
    elif opcode == 0b0100011:  # S-type
        imm_u = (data_slice(Instr, 31, 25) << 5) | data_slice(Instr, 11, 7)
        imm = sign_expend(imm_u, 12)
        rs2 = data_slice(Instr, 24, 20)
        rs1 = data_slice(Instr, 19, 15)
        funct3 = data_slice(Instr, 14, 12)
        if funct3 == 0b000:
            micro_opt.name = "sb"
            micro_opt.write_mem = True
            micro_opt.size = 0
            if rs1 == 2:
                micro_opt.stack = True
        elif funct3 == 0b001:
            micro_opt.name = "sh"
            micro_opt.write_mem = True
            micro_opt.size = 1
            if rs1 == 2:
                micro_opt.stack = True
        elif funct3 == 0b010:
            micro_opt.name = "sw"
            micro_opt.write_mem = True
            micro_opt.size = 2
            if rs1 == 2:
                micro_opt.stack = True
        else:
            No_Such_Instr = True

    elif opcode == 0b1100011:  # B-type
        rs2 = data_slice(Instr, 24, 20)
        rs1 = data_slice(Instr, 19, 15)
        funct3 = data_slice(Instr, 14, 12)
        idx_3125 = data_slice(Instr, 31, 25)
        idx_117 = data_slice(Instr, 11, 7)
        imm_pre = (data_slice(idx_3125, 6, 6) << 12) | (data_slice(idx_117, 0, 0) << 11) | (data_slice(idx_3125, 5, 0) << 5) | (
                    data_slice(idx_117, 4, 1) << 1)
        imm = sign_expend(imm_pre, 13)
        if funct3 == 0b000:
            micro_opt.name = "beq"
            micro_opt.jump = True
        elif funct3 == 0b001:
            micro_opt.name = "bne"
            micro_opt.jump = True
        elif funct3 == 0b100:
            micro_opt.name = "blt"
            micro_opt.jump = True
        elif funct3 == 0b101:
            micro_opt.name = "bge"
            micro_opt.jump = True
        elif funct3 == 0b110:
            micro_opt.name = "blt"  # bltu
            micro_opt.jump = True
            micro_opt.unsigned = True
        elif funct3 == 0b111:
            micro_opt.name = "bge"  # bgeu
            micro_opt.jump = True
            micro_opt.unsigned = True
        else:
            No_Such_Instr = True
    else:
            No_Such_Instr = True
    if No_Such_Instr:
        print("no such instruction 0x%08x"% Instr)

    return micro_opt, rs1, rs2, rd, imm